home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-27 | 35.5 KB | 835 lines | [TEXT/pdos] |
-
-
- 1
-
-
- XCMD and XFCN: The Magic Hooks That Extend HyperTalk
-
- This documentation by Andy Stadler and Darin Acquistapace
- For HyperCard IIGS 1.1
-
- cApple Computer, Inc. 1987, 1989-1992
- All Rights Reserved.
-
-
- (Thanks to Ted Kaehler who wrote the original of this paper)
-
-
- XCMD's and XFCN's are a powerful method of extending the capabilities
- of HyperCard IIGS. Quite simply, an XCMD or XFCN is a code resource
- containing any compiled code the user wishes. XCMD's and XFCN's can be
- used where HyperTalk might be too slow (eg complicated sorts), as
- device or hardware controllers (eg LaserDisk controllers) or for
- anything else the programmer desires.
-
- A note on terminology. For most purposes, XCMD's and XFCN's are
- identical, so unless necessary to draw a distinction, this document
- will use the term XCMD to describe both types of X-thing.
-
- XCMD's are inserted into the normal search path, in locations similar
- to standard HyperTalk handlers. The resource forks of the current
- stack, home stack and hypercard itself are searched and any XCMD
- therein becomes part of the language. Just as a handler may either
- extend the language or actually replace features, so may an XCMD. The
- inheritance path is:
-
- Button (or Field)
- Card
- Stack
- Any XCMD currently open because it owns an XWindow(s).
- Stack XCMD
- Home
- Home XCMD
- XCMD in HyperCard application file
- HyperCard command
-
- An XCMD or XFCN is a code resource of types $801E and $801F
- respectively. In addition name resources (type $8014) must exist
- because the language can only reference these resources by name. You
- can create an XCMD and it's name with RezIIGS, and you can move them
- from file to file with RMover, the ResCopy XCMD, or with any other
- resource moving tool.
-
- XCMD's are called using the standard Pascal/toolbox stack based method.
- They are called in full native mode, with a single parameter pushed
- onto the stack. On exit, the XCMD must pop the parameter, and must
- return with the same processor mode and direct page. All other
- registers may be trashed. These rules are important for assembly
- language programmers but high-level languages use glue to take care of
- all the "dirty work."
-
- Once inside the XCMD, the programmer has almost limitless capabilities.
- The user may request memory, and make OS or ToolBox calls. New
- extensions in HyperCard IIGS version 1.1 allow XCMD's to own windows
- and interact with the user through them. The only practical limitation
- of XCMD's is that the entire package including all code and data must
- fit in a single OMF segment - giving an upper bound of 64k!
-
- An XCMD can be expressed in Pascal with the following description:
-
- PROCEDURE EntryPoint(paramBlock: XCmdPtr);
-
- All information is interchanged with HyperCard IIGS through a structure
- called an XCmdBlock. Note that this is the only parameter ever passed
- to an XCMD. If the HyperTalk script passes any parameters, they will
- be installed into the parameter block itself. The XCmdBlock appears as
- follows:
-
- XCmdPtr = ^XCmdBlock;
- XCmdBlock = RECORD
- paramCount: INTEGER;
- params: ARRAY[1..16] OF Handle;
- returnValue: Handle;
- passFlag: BOOLEAN;
- userID: INTEGER;
- returnStat: BOOLEAN;
- END;
-
- The fields are defined as follows:
-
- paramCount is the number of arguments in the XCMD invocation. This
- does not include the XMCD name itself. For example, the command Flash
- 5 has a parmCount of 1.
-
- params is an array of handles. Each handle contains a zero-terminated
- string containing a single parameter from the invocation. For example,
- the command Flash 5 will create a single handle in params[1] containing
- '5' and a zero terminater. The other 15 entries are undefined.
-
- returnValue is used in three different ways. For XCMD's, a string
- returned here will be placed into "the result". For XFCN's, the
- function result is returned here, and "the result" is never affected.
- Finally, for either type, if returnStat is TRUE, the string here will
- be displayed as a script error (see returnStat below).
-
- In either case, the result is returned by creating a new handle and
- putting the result in it (zero terminated string). HyperCard IIGS will
- dispose the handle. The field is initialized to NIL before calling the
- XCMD, so if you wish to return the empty string, just leave the field
- alone.
-
- passFlag is a flag telling HyperCard IIGS how to complete the message.
- If it returns FALSE (its unmodified state) the XCMD has handled the
- message. If the code sets passFlag to TRUE, the message will continue
- to pass through the message heirarchy. Setting passFlag to true is
- exactly equivalent to invoking the command pass messageName in a
- HyperTalk handler.
-
- userID is a IIGS user ID. A unique ID will be assigned to each
- concurrent invocation of each different XCMD. That is, no two running
- XCMDs will ever be given the same ID at the same time, even if they
- recurse into each other. The XCMD should use this ID for all memory
- requests. Please clean up all your handles before exiting!
-
- returnStat allows XCMDs to report an error using the script error
- reporting mechanism. If returnStat is TRUE, the returnValue will be
- displayed in a script error dialog box, along with "script" or "cancel"
- buttons. This allows XCMD to cleanly report errors in parameters or
- usage.
-
-
- MACHINE STATE ON XCMD LAUNCH
-
- When you launch an XCMD, the following machine state may be depended
- on:
-
- Full native 16 bit mode.
- The current grafport is the card window.
- Resource search path is set to infinite search from the current stack
- file on down.
-
-
- MAKING CALLBACKS
-
- At any time, an XCMD may call back into HyperCard IIGS. From a high-
- level language the call descriptions below should be enough. For
- assembly, the following notes should help:
-
- o The callback routines are accessed similar to pascal or toolbox
- procedures: push a result space if function, push parameters. The X
- register is loaded with the call #, and the "HyperCard IIGS Vector" is
- then called as a subroutine: JSL $E10220. Callbacks follow mostly the
- same rules as Tool Calls: -- All params and results are passed on the
- stack -- The A,X,Y registers are undefined (note: no error codes or C
- flag) -- Databank and Direct Page -will- be preserved.
- o HyperCard IIGS assumes that XCMDs will place their global data
- adjacent to the XCMD code. Therefore, to aid the XCMD, the data bank
- will be set to the same bank as the XCMD's code before it is called.
- If the XCMD wishes to place globals elsewhere, it is free to modify the
- data bank register, as HyperCard IIGS will restore the bank register
- correctly when the XCMD completes.
- o The technique for returning strings as function results is as
- follows: (1) Push a pointer to a string-sized result space. (2)
- Push params. (3) Load X with function number. (4) Call entry point.
- Callback will pop params, but leaves the result pointer, so (5) pop
- the result pointer. This is the method used by the MPW PascalIIGS
- compiler.
-
- In addition, notice that several of the calls create and return a new
- handle; this handle is not created with the XCMD's user ID. Do not
- ever DisposeAll(parms^.userID), for three reasons: 1. If you have
- created data and passed it back through a callback, HyperCard IIGS
- might still be using it; 2. The user ID's may be re-used, and some
- XCMD's keep data around from one invocation to the next. If you
- DisposeAll with your current userID, you might destroy data held by an
- earlier XCMD. 3. The user ID is preserved when calling an XCMD that
- owns XWindows in response to window events, a single XCMD may own
- multiple windows and executing a DisposeAll will release memory that
- may still be required in conjunction with other windows.
-
- The following callbacks have been defined:
-
- PROCEDURE SendCardMessage(msg: Str255); Asm #1
-
- Send a HyperCard message (a command with arguments) to the current
- card.
-
-
-
- FUNCTION EvalExpr(expr: Str255): Handle; Asm #2
-
- Evaluate a HyperCard expression and return the answer. The answer is a
- handle to a zero-terminated string.
-
- FUNCTION StringLength(strPtr: Ptr): LongInt; Asm #3
-
- Count the characters from where strPtr points until the next zero byte.
- Does not count the zero itself. strPtr must be a zero-terminated
- string.
-
- FUNCTION StringMatch(pattern: Str255; target: Ptr): Ptr; Asm #4
-
- Perform case-insensitive match looking for pattern anywhere in target,
- returning a pointer to first character of the first match, in target
- or NIL if no match found. pattern is a Pascal string, and target is a
- zero-terminated string.
-
- PROCEDURE SendHCMessage(msg: Str255); Asm #5
-
- Send a HyperCard message (a command with arguments) to HyperCard.
-
- PROCEDURE ZeroBytes(dstPtr: Ptr; longCount: LongInt); Asm #6
-
- Write zeros into memory starting at dstPtr and going for longCount
- number of bytes.
-
- FUNCTION PasToZero(str: Str255): Handle; Asm #7
-
- Convert a Pascal string to a zero-terminated string. Returns a handle
- to a new zero-terminated string. The caller must dispose the handle.
-
- PROCEDURE ZeroToPas(zeroStr: Ptr; VAR pasStr: Str255); Asm #8
-
- Fill the Pascal string with the contents of the zero-terminated string.
- You create the Pascal string and pass it in as a VAR parameter. Useful
- for converting the arguments of any XCMD to Pascal strings.
-
- FUNCTION StrToLong(str: Str31): LongInt; Asm #9
-
- Convert a string of ASCII decimal digits to an unsigned long integer.
-
- FUNCTION StrToNum(str: Str31): LongInt; Asm #10
-
- Convert a string of ASCII decimal digits to a signed long integer.
- Negative sign is allowed.
-
- FUNCTION StrToBool(str: Str31): BOOLEAN; Asm #11
-
- Convert the Pascal strings 'true' and 'false' to booleans.
-
- FUNCTION StrToExt(str: Str31): Extended; Asm #12
-
- Convert a string of ASCII decimal digits to an extended floating point
- value.
-
-
-
-
- FUNCTION LongToStr(posNum: LongInt): Str31; Asm #13
-
- Convert an unsigned long integer to a Pascal string.
-
- FUNCTION NumToStr(num: LongInt): Str31; Asm #14
-
- Convert a signed long integer to a Pascal string.
-
- FUNCTION NumToHex(num: LongInt; nDigits: INTEGER): Str31; Asm #15
-
- Convert an unsigned long integer to a hexadecimal number and put it
- into a Pascal string.
-
- FUNCTION BoolToStr(bool: BOOLEAN): Str31; Asm #16
-
- Convert a BOOLEAN to 'true' or 'false'.
-
- FUNCTION ExtToStr(num: Extended): Str31; Asm #17
-
- Convert an extended long integer to decimal digits in a string.
-
- FUNCTION GetGlobal(globName: Str255): Handle; Asm #18
-
- Return a new handle to a zero-terminated string containing the value of
- the specified HyperTalk global variable. The caller must dispose this
- handle.
-
- PROCEDURE SetGlobal(globName: Str255; globValue: Handle); Asm #19
-
- Set the value of the specified HyperTalk global variable to be the
- zero-terminated string in globValue. The contents of the Handle are
- copied, so you must still dispose it afterwards.
-
- FUNCTION GetFieldByName(cardFieldFlag: BOOLEAN; fieldName:
- Str255): Handle; Asm #20
-
- Return a handle to a zero-terminated string containing the value of
- field fieldName on the current card. You must dispose the handle.
- cardFieldFlag set to false indicates background, instead of card,
- field.
-
- FUNCTION GetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum:
- INTEGER): Handle; Asm #21
-
- Return a handle to a zero-terminated string containing the value of
- field fieldNum on the current card. You must dispose the handle.
-
- FUNCTION GetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER):
- Handle; Asm #22
-
- Return a handle to a zero-terminated string containing the value of the
- field while ID is fieldID. You must dispose the handle.
- PROCEDURE SetFieldByName(cardFieldFlag: BOOLEAN; fieldName:
- Str255; fieldVal: Handle); Asm #23
-
- Set the value of field fieldName to be the zero-terminated string in
- fieldVal. The contents of the Handle are copied, so you must still
- dispose it afterwards.
-
- PROCEDURE SetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum:
- INTEGER; fieldVal: Handle); Asm #24
-
- Set the value of field fieldNum to be the zero-terminated string in
- fieldVal. The contents of the Handle are copied, so you must still
- dispose it afterwards.
-
- PROCEDURE SetFieldByID(cardFieldFlag:BOOLEAN; fieldID: INTEGER;
- fieldVal: Handle); Asm #25
-
- Set the value of the field whose ID is fieldID to be the zero-
- terminated string in fieldVal. The contents of the Handle are copied,
- so you must still dispose it afterwards.
-
- FUNCTION StringEqual(str1,str2: Str255): BOOLEAN; Asm #26
-
- Return true if the two strings have the same characters. Case
- insensitive compare of the strings.
-
- PROCEDURE ReturnToPas(zeroStr: Ptr; VAR pasStr: Str255); Asm #27
-
- zeroStr points into a zero-terminated string. Collect the characters
- from there to the next carriage Return or the end of the string, and
- return them in the Pascal string pasStr.
-
- PROCEDURE ScanToReturn(VAR scanPtr: Ptr); Asm #28
-
- Move the pointer scanPtr along a zero-terminated string until it points
- at a Return character or a zero byte.
-
- PROCEDURE ScanToZero(VAR scanPtr: Ptr); Asm #29
-
- Move the pointer scanPtr along a zero-terminated string until it points
- at a zero byte.
-
- FUNCTION GSToPString(src: GSString255Hndl): Str255; Asm #30
-
- Convert a GS/OS Class 1 input string (length word + text) into a pascal
- string. If the source string has more than 255 characters, only the
- first 255 will be copied.
-
- FUNCTION PToGSString(src: Str255): GSString255Hndl; Asm #31
-
- Convert a Pascal string to a GS/OS Class 1 input string (length word +
- text). If the source string is empty, NIL is returned; otherwise a new
- handle is created and filled with the text.
-
- FUNCTION CopyGSString(src: GSString255Hndl): GSString255Hndl;
- Asm #32
- Simply copies a GS/OS Class 1 input string (length word + text). If
- the handle is NIL or empty or contains a length word of zero, NIL is
- returned, otherwise a new handle is created with an exact duplicate of
- the input text.
-
- FUNCTION GSConcat(src1, src2: GSString255Hndl): GSString255Hndl;
- Asm #33
- Concatenates two GS/OS Class 1 input strings (length word + text). If
- both inputs are NIL or empty or contain a length word of zero, NIL is
- returned, otherwise a new handle is created with the inputs placed end-
- to-end.
-
- FUNCTION GSStringEqual(src1, src2: GSString255Hndl): BOOLEAN;
- Asm #34
- Performs a case-insensitive comparison of two GS/OS Class 1 input
- strings (length word + text). If the strings are equal, TRUE is
- returned. NIL or empty handles are considered to have length of zero,
- and two strings of length zero will be judged equal.
-
- FUNCTION GSToZero(src: GSString255Hndl): Handle; Asm #35
-
- Converts a GS/OS Class 1 input string (length word + text) into a zero-
- terminated string. Even if the input string is empty (NIL or empty
- handle or length = 0) a zero handle will be created- an empty zero
- handle has length 1 and contains only a zero terminator.
-
- FUNCTION ZeroToGS(src: Handle): GSString255Hndl; Asm #36
-
- Converts a zero handle into a GS/OS Class 1 input string (length word +
- text). If the source handle is empty or has length zero, NIL is
- returned, otherwise a new handle is created, the length word is set,
- and the text is copied into it.
-
- The next four calls are designed to assist XCMD's which use resources.
- The IIGS Resource Manager prior to System 6.0 does not support "named"
- resources, but there is a standard format for storing names of
- resources in "name resources". These callbacks provide a simple
- library of routines to assist identifying resources by name. See the
- IIGS ToolBox Reference, vol. 3, for more information.
-
- FUNCTION LoadNamedResource(whichType: ResType; name: Str255): Handle;
- Asm #37
-
- Searches for the resource of this type and name and loads it. If the
- resource is not found, returns NIL. Respects the current resource
- search path: Starts from the current file, and only goes as deep as
- the specified depth.
-
- FUNCTION FindNamedResource(whichType: ResType; name: Str255; VAR
- homeFile: INTEGER; VAR id: ResID): BOOLEAN; Asm #38
-
- Searches for the resource of this type and name. If the specified
- resource is found, returns TRUE, and file and id are set to the
- containing file and the resource ID. If the resource is not found,
- returns FALSE, and the file and ID are undefined. Respects the current
- resource search path: Starts from the current file, and only goes as
- deep as the specified depth. Note: It is important to take note of
- the file number, because it would be possible to have two resources, in
- different files, with the same ID, and different names: If you asked
- for the deeper of the two, and then attempted to load it by ID, you
- would get the shallower one.
-
- PROCEDURE SetResourceName(whichType: ResType; id: ResID; name:
- Str255); Asm #39
-
- Changes the name of a given resource to "name". Respects the current
- resource search path: Starts from the current file, and only goes as
- deep as the specified depth. If no resource can be found within the
- search criteria, nothing will happen. If you set a resource name to
- the empty string, it has no name, and may then only be referred to by
- type and ID.
-
- The IIGS resource manager does not directly support named resources.
- One effect of this is that you can delete resources, but the names
- remain. Therefore, when deleting a resource, named or not, it is a
- good idea to call this routine and set the resource's name to the empty
- string - thus clearing out the name.
-
- This routine will not add a name unless there is a corresponding target
- resource of the given type and ID. If you are adding a new resource,
- then, you must first add the resource, and then you may give it a name.
-
- FUNCTION GetResourceName(whichType: ResType; id: ResID): Str255; Asm
- #40
-
- Returns the name of a given resource. Respects the current resource
- search path: Starts from the current file, and only goes as deep as
- the specified depth. If the resource has no name, or if the resource
- doesn't exist, you will get an empty string in both cases. Thus, you
- must use different means to determine the existence of the resource
- itself. This call only identifies the existence of a name - not the
- resource itself.
-
- The next two calls are designed to assist XCMD's which wish to use the
- IIGS sound hardware (referred to herein as the "DOC chip"). These
- callbacks provide a very simple form of arbitrarion, by allowing the
- XCMD's to reserve the DOC for their own use. If you leave the XSound
- activated, HyperCard IIGS will never be able to make another sound
- (until re-launched) so if you must use these callbacks, PLEASE be sure
- to call EndXSound at an appropriate time. It is not automatic.
-
- PROCEDURE BeginXSound; Asm #41
-
- Indicates to HyperCard IIGS that an XCMD would like to take over
- control of the DOC chip. After this call, HyperCard IIGS will never
- emit sound from the speaker. The play command will simply fall
- through. You MUST execute the EndXSound call for HyperCard IIGS to
- make any more sounds.
-
- PROCEDURE EndXSound; Asm #42
-
- Indicates to HyperCard IIGS that an XCMD has completed usage of the DOC
- chip. After this call is made, HyperCard IIGS may resume its own use
- of the DOC chip, and may begin making sounds.
-
- The next two calls are designed to assist XCMD's and which wish to do
- image processing. They provide an easy way to get images in and out of
- HyperCard IIGS. This could be used in conjunction with a scanner or
- digitized XCMD, for example. DO NOT use these calls during painting,
- because there are a number of other buffers which are also involved.
-
- PROCEDURE GetMaskAndData(VAR mask: LocInfo; VAR data: LocInfo);
- Asm #43
-
-
- This call actually does two things: first, HyperCard IIGS will update
- its internal buffers to contain the up-to-date image; second, it will
- return the LocInfo records of the two image buffers. The data buffer
- is a card-sized buffer which contains the image of "the card". The
- mask buffer is a similar sized buffer which contains the "opaque" layer
- of the card. In the opaque layer, 0 = transparent and 1 = opaque.
- Note: ANY activities subsequent to this call can cause these buffers
- to change, so an xcmd must finish using the buffers, or at least make
- local copies, before making any of the callbacks which might update the
- screen, change cards, etc.
-
- PROCEDURE ChangedMaskAndData(whatChanged: INTEGER); Asm #44
-
- This callback is used by XCMDs which actually change the picture on a
- card and wish it to be saved in the stack. An XCMD which wants to
- change a picture should contain the following sequence of operations:
- GetMaskAndData;
- MakeChanges;
- ChangedMaskData(whatChanged);
-
- The change codes are one of the following:
-
- Code Meaning
- 0 No changes were made to the buffers, but please update the
- screen. This is a good way to update the card window if an XCMD has
- been drawing in it.
- 1 The buffers were modified, but the XCMD does not wish to save the
- changes. Please restore them to their original state.
- 2 New data and mask have been placed in the buffers; or, new data
- was supplied and use the original mask.
- 3 New data was written, and this new image requires a mask buffer
- of "all transparent". HyperCard IIGS will fill the mask with zeros
- before saving the pictures.
- 4 New data was written, and this new image requires a mask buffer
- of "all opaque". HyperCard IIGS will fill the mask with ones before
- saving the pictures.
- 5 New data was written. HyperCard IIGS will compute a new mask
- buffer using the following algorithm: all white data pixels become
- transparent; all non-white data pixels become opaque.
-
- The callbacks listed below are new to HyperCard IIGS version 1.1.
- Attempting to execute these callbacks with a version of HyperCard IIGS
- prior to 1.1 will cause HyperCard to crash. Care must be taken that
- the correct version of HyperCard is in use before using these
- callbacks. Sample Pascal source is included below to illustrate a
- means of checking the version from an XCMD.
-
- FUNCTION CorrectVersion: BOOLEAN;
- { This returns true if the version of HyperCard is >= minVersion }
- CONST
- minVersion = '1.1';
- VAR
- tempHandle: Handle;
- tempStr: Str255;
- BEGIN
- tempHandle := EvalExpr('the version');
- ZeroToPas(tempHandle^, tempStr);
- IF temphandle <> NIL THEN DisposeHandle(tempHandle);
- CorrectVersion := tempStr >= minVersion;
- END; {CorrectVersion}
-
-
- PROCEDURE PointToStr(pt: Point; VAR str: Str255); Asm #45
-
- This callback converts a point to a Pascal string. This is typically
- used when an XCMD needs to return a point to HyperCard as an interim
- measure before calling PasToZero to convert the new Pascal string to a
- zero-terminated string.
-
- PROCEDURE RectToStr(rct: Rect; VAR str: Str255); Asm #46
-
- Similar to PointToStr, this callback converts a rect to a Pascal
- string.
-
- PROCEDURE StrToPoint(str: Str255; VAR pt: Point); Asm #47
-
- The compliment of PointToStr, this callback converts a Pascal string to
- a point. Missing coordinates will be converted to zero. For example
- the string "5,15" will be converted to a point with the horizontal
- coordinate being five and the vertical coordinate being 15 while the
- string "8" would result in a point with a horizontal coordinate of
- eight and a vertical coordinate of zero.
-
- PROCEDURE StrToRect(str: Str255; VAR pt: Point); Asm #48
-
- Similar to StrToPoint, this callback converts a string to a rect.
-
- FUNCTION NewXWindow(boundsRect: Rect; title: Str31;
- visible: BOOLEAN; wStyle: INTEGER): WindowPtr;
- Asm #49
-
- This callback creates an XWindow. An XWindow is very similar to a
- standard with several key exceptions noted below. BoundsRect defines
- the location and size of the content region of the window. Note that
- the actual size of the window frame depends upon the window style.
- Title is a Pascal string of up to 31 characters which is used to
- reference the window by name from HyperTalk. The visible parameter
- determines indicates whether the window will be created initially
- visible. WStyle is one of the following constants declared in the
- HyperXCMD interface file.
-
- xWindoidStyle 0 Window has a grey drag bar and close box.
- xRectStyle 1 A simple rectangle outlines the this style window.
- xShadowStyle 2 A rectangle with a drop shadow on the bottom and right sides.
- xDialogStyle 3 Identical in appearance to a dialog box.
-
- As noted above, XWindows are very similar to standard windows obtained
- via the NewWindow toolbox call. The differences include: (1) The
- programmer must never alter the wRefCon field of the window record.
- Instead, use the SetXWindowValue callback if you wish to save a value
- along with the window. (2) The wFrameBits is inaccessible to the user
- and must not be changed. (3) The programmer should not call
- CloseWindow on this window, instead, they must use the CloseXWindow
- callback which will properly dispose of additional memory HyperCard has
- allocated for the window and send the proper close event to the XCMD.
-
- An XCMD that creates an XWindow has several additional
- responsibilities. These include responding to events specific to the
- XWindow(s) it creates as well as disposing of any additional memory the
- XCMD may have allocated when creating the XWindow. See the section
- "Care and Feeding of Your New XWindow" below for complete details on
- responding to XWindow events.
-
- PROCEDURE SetXWIdleTime(window: WindowPtr; interval: LongInt);
- Asm #50
-
- This callback instructs HyperCard how often (in ticks) the XCMD would
- like to receive null events for each XWindow it has created. The
- default is zero which indicates the XCMD does _not_ wish to receive
- null events. Care should be taken that an XWindow does not slow down
- HyperCard unnecessarily by receiving more null events than it
- absolutely requires. A clock XWindow, for instance, would most likely
- not need a null event more often than once per second at the most.
-
- PROCEDURE CloseXWindow(window: WindowPtr); Asm #51
-
- This callback sends a closeEvent to the owner of the indicated XWindow,
- releases all memory HyperCard has allocated for internal use regarding
- the XWindow, and closes the window via a CloseWindow call.
- Additionally, if the owner XCMD of the window being closed no longer
- owns any windows, its code is disposed of and its memory ID released if
- no calls are currently pending for it or marked for later disposal if
- calls are currently pending. The XCMD may save itself from being
- disposed if it opens additional windows after it is marked for disposal
- but still awaiting pending or recursive calls.
-
- PROCEDURE HideHCPalettes; Asm #52
-
- This callback hides all currently open HyperCard windows including all
- XWindows and all built-in windows except for the card window.
- Additionally, it records the visible state of each window when the call
- was executed so that a subsequent call to ShowHCPalettes can restore
- all windows that were visible. The xHidePalettesEvt XWindow message is
- sent to every XWindow when this call is executed. This callback is
- typically used when it is necessary to clear the screen of
- obstructions, such as when using the Apple II Video Overlay Card.
-
- PROCEDURE ShowHCPalettes; Asm #53
-
- The compliment to HideHCPalettes, this callback shows all windows that
- were visible at the time of the HideHCPalettes call and sends the
- xShowPalettesEvt to every XWindow.
-
- FUNCTION GetXWindowValue(window: WindowPtr): LongInt; Asm #55
-
- This callback retrieves the value of an XWindow previously set by the
- SetXWindowValue callback below. This value is inistailized to zero
- when the XWindow is created.
-
- PROCEDURE SetXWindowValue(window: WindowPtr; customValue:
- LongInt); Asm #54
-
- This callback allows the XCMD owner of an XWindow to save a LongInt
- (four byte) sized value along with an XWindow it creates. Since an
- XCMD may own multiple XWindows, this callback allows the XCMD to save a
- unique value along with specific windows. Typically, this value would
- contain a picture handle for updates or a handle to a record containing
- data needed for the particular XWindow.
-
-
- GETTING STARTED
-
- It is strongly suggested that the XCMD author start by copying the
- given sample XCMDs and modifying them. The code itself is quite
- simple, however the steps to build an XCMD are somewhat complex. The
- examples given are ABeep, PBeep and CBeep. They each create a command
- which simply beeps the speaker a given number of times. Each version
- comes in its own folder with a make file, program source, and a rez
- source file. These samples are included in MPW IIGS and APW format.
-
- To make an XCMD, set the MPW directory to that folder, and select
- Build.... from the build menu. Type the XCMD name into the dialog, and
- the build process should begin. The final step in a successful build
- is to copy the file containing the resource onto a ProDOS diskette.
- Now you must use the supplied RMover utility. This is a simple
- resource mover with which you may add the new resource to an existing
- stack file. When you use Rmover, be sure to click the "Types" button
- and select type $801E - XCMD, OMF.
-
- After you place the XCMD in a stack, launch HyperCard IIGS and open the
- stack containing the XCMD. To invoke the XCMD, simply type it's name
- and any required parameters into the message box. From here on out,
- it's welcome to the wonderful world of debugging.
-
-
-
- To create a new XCMD, copy the entire folder and rename every
- occurrence you can find of the resource name, to the new name. That
- is, rename every file, -and- open the text files and rename every
- occurrence inside.
-
-
- NOT FOR THE FAINT OF HEART
-
- If you really want to start messing around, I urge you to read and
- completely understand the link commands and the rez source. Many of
- the high-level compilers especially like to create lots of segments,
- and the makefile goes to great lengths to create a file which has (1) a
- single segment and (2) an entry point at the 1st byte in the segment.
-
-
- CARE AND FEEDING OF YOUR NEW XWINDOW
- External commands that create XWindows are kept in memory after they
- terminate so that they may be called in response to events concerning
- the XWindows they created. An XCMD can determine whether it has been
- called from a script or the message box or in response to an event by
- checking the paramCount field of the parameter block. If this value is
- negative, the XCMD has been called in response to an event. The
- following Pascal code fragment illustrates this concept.
-
- BEGIN {SampleXCMD}
- { If the paramCount is negative, we have been called
- in
- response to an event }
- IF paramPtr^.paramCount < 0 THEN BEGIN
- HandleEvents;
- EXIT(SampleXCMD);
- END; {if}
-
- { program continues... }
-
- The Events an External Command Will Receive
- Upon calling an XCMD in response to an event, the following conditions
- are true:
-
- (1) The current port is set to the XWindow which the
- event deals with.
- (2) The memory ID field of the parameter block is the
- same as when the
- XCMD initially created the XWindow.
- (3) The first parameter is a pointer to an XWEventInfoPtr
-
- The structure of an XWEventInfoPtr is as follows:
-
- eventWindow: WindowPtr;
- event: EventRecord;
- eventParams: ARRAY[1..9] OF LongInt;
- eventResult: Handle;
-
- The following is a list of all events an external command can receive
- along with a description of the event. Some of the events are standard
- system events while others are generated by HyperCard. In all cases
- the event record consists of the following fields:
-
- what: INTEGER; { event code }
- message: Longint; { event message }
- when: Longint; { ticks since startup }
- wher : Point; { mouse location }
- modifiers: INTEGER; { modifier flags }
-
-
- HyperCard Event - "xOpenEvt"
- xOpenEvt is always the first event sent to any XWindow. This event is
- sent to any new XWindows immediately after the parent XCMD terminates.
- No events will be sent to an XWindow before this event.
-
- HyperCard Event - "xCloseEvt"
- This is HyperCard's method of notifying the XCMD that a window that it
- created is being closed. At the time of the event, the window is still
- present and visible. The window will be closed immediately following
- the event. The owner XCMD should not call CloseXWindow or close the
- window in any other means when it receives this event. HyperCard will
- handle closing the window when the XCMD terminates. XCMDs will
- typically use this event to dispose of any additional memory they have
- allocated for the XWindow.
-
- HyperCard Event - "xHidePalettesEvt"
- This event is sent to all XWindows when an external command executes
- the HideHCPalettes callback. An external command may wish to
- deallocate memory or take other action when the user hides their window
- in this manner.
-
- HyperCard Event - "xShowPalettesEvt"
- This event is sent to all XWindows when an external command executes
- the ShowHCPalettes callback. An external command may need to prepare
- itself to handle update events, etc, if it has deallocated the memory
- when being hidden.
-
- HyperCard Event - "xCursorWithin"
- This event is sent to an XWindow when the mousecursor enters therect of
- their window. The owner XCMD can then set the cursor to a custom shape
- if desired using the toolbox. If they do not wish to handle the
- changing of the cursor shape, the external command should set the
- passFlag of the parameter block to TRUE so that HyperCard will handle
- the cursor itself. Since this message is sent repeatedly, as long as
- the cursor is within the window, the XCMD should determine whether it
- has already changed the cursor shape before doing so again to avoid
- flickering of the cursor and slowing down the CPU.
-
- System Event - "UpdateEvt"
- This event indicates the all or part of the specified window needs to
- be updated. It is the responsibilty of the owner external of each
- window to handle redrawing the contents of the window in response to
- this event.
-
- System Event - "MouseDownEvt"
- The user has pressed the mouse button while the mouse pointer was
- within an external window. The external command will commonly handle
- tracking the mouse click manually, or call FindControl and have the
- control manager do so.
-
- System Event - "NullEvt"
- This event will only be sent if the XCMD/XFCN has enabled idle events
- by setting the idle interval to a value other than zero with the
- SetXWIdleTime callback. See the description of this callback above for
- more information regarding using null events.
-
-
- NOTES ABOUT XCMDS THAT OPEN XWINDOWS
- An XCMD that creates an XWindow is treated differently from an XCMD
- that doesn't. The following section details differences the XCMD
- author needs to be aware of.
-
- 1) XCMDs that create external windows are kept in memory as long as
- any XWindows that XCMD created are open.
- 2) XWindow XCMDs should not assume that they own only one window.
- Subsequent calls to the XCMD may create additional windows. The XCMD
- should use the windowPtr passed and the GetXWindowValue and
- SetXWindowValue calls to determine the appropriate action to take in
- response to a particular event.
- 3) The same Memory Manager user ID is passed to an XWindow owner XCMD
- as long as any of the XWindows the XCMD owns are open. The XCMD should
- not perform a DisposeAll on its memory ID because other windows that
- the XCMD is responsible for are still open.
- 4) The wFrameBits field of an XWindow is inaccessible to an XCMD,
- XCMDs should not attempt to modify the standard window attributes of an
- XWindow.
- 5) XWindows may remain open throughout various stacks. Any resources
- needed by a particular XWindow should be detached and maintained by the
- XCMD when the window is opened.
- 6) XCMDs that have currently open XWindows are inserted into the
- heirarchy immediately after the stack script of the current stack.
- XCMDs that open XWindows should be aware that they may be called from
- HyperTalk after leaving their parent stack.
-